/**
 * @file   zdefs.h
 * @author karpar Hu <huzhili@gmail.com>
 * @date   Mon Apr 27 17:14:11 2009
 * 
 * @brief  extracted for apple's autozone, predefines some types, and bit ops!
 * 
 * 
 */

#ifndef _ZDEFS_H_
#define _ZDEFS_H_

#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>


const char *prelude(void);

#if defined(DEBUG)
#define ASSERTION(expression) if(!(expression)) {       \
    fprintf(stderr, "*** %s Assertion %s %s.%d\n", prelude(), #expression, __FILE__, __LINE__); \
    __builtin_trap();                                                   \
  }
#else
#define ASSERTION(expression) (void)(expression)
#endif

typedef unsigned long usword_t;
typedef signed long sword_t;

enum {
  page_size = 0x1000u,          /* vm_page_size,but faster */
  page_size_log2 = 12,          /* ilog2 of page_size */

  bits_per_bytes = 8,           /* standard bits per byte */
  bits_per_bytes_log2 = 3,      /* ilog2 of bits per byte */

  is_64BitWord = sizeof(usword_t) == 8u,
  is_32BitWord = sizeof(usword_t) == 4u,

  bytes_per_word = is_64BitWord ? 8u : 4u, /* number of bytes in an unsigned long word */
  bytes_per_word_log2 = is_64BitWord ? 3u : 2u, /* ilog2 of bytes in an unsigned long word */

  bits_per_word = is_64BitWord ? 64u : 32u, /* standard bits per word */
  bits_per_word_log2 = is_64BitWord ? 6u : 5u, /* ilog2 of bits per word */

  bytes_per_quad = 16,          /* bytes in a quad word(vector) */
  bytes_per_quad_log2 = 4,      /* ilog2 of bytes_per_quad */

  bits_per_quad = 128,          /* bits in a quad word */
  bit_per_quad_log2 = 7,        /* ilog2 of bits_per_quad */

  bit_mask = (usword_t)(bits_per_word - 1), /* mask to get bit index of word */

  all_zeros = (usword_t)0,      /* a word of all 0 bits */
  all_ones = ~all_zeros,         /* a word of all 1 bits */

  not_found = all_ones,         /* a negative result of search methods */

  pointer_alignment = 2u,       /* bit alignment required for pointers */
  block_alignment = 4u, /* bit alignment required for allocated blocks */
};

/** 
 * test if all bits in x is one
 * 
 * @param x 
 * 
 * @return false or true
 */
inline const bool is_all_ones(usword_t x) 
{
  return !(~x);
}

/** 
 * test if all bits in x is zero
 * 
 * @param x the variable to be tested
 * 
 * @return true or false
 */
inline const bool is_all_zeros(usword_t x)
{
  return !x;
}

inline void *displace(void *address, const intptr_t offset)
{
  return (void *)((char *)address + offset);
}
/** 
 * get minor of tow
 * 
 * @param a 
 * @param b 
 * 
 * @return minor on
 */
static inline const usword_t min(usword_t a, usword_t b)
{
  return a < b ? a : b;
}
/** 
 * get larger one of two
 * 
 * @param a 
 * @param b 
 * 
 * @return the bigger one
 */
static inline const usword_t max(usword_t a, usword_t b)
{
  return a > b ? a : b;
}
/** 
 * get bits masks
 * 
 * @param n the number of bits
 * 
 * @return bit mask
 */
static inline const usword_t mask(usword_t n) 
{
  ASSERTION(0 < n && n <= bits_per_word);
  return (2L << (n-1)) - 1;
}
/** 
 * judge if a number is the power of 2
 * 
 * @param x the number
 * 
 * @return true if is, otherwise
 */
static inline const bool is_power_of_2(usword_t x) 
{
  return ((x - 1) & x) == 0;
}
/** 
 * count the leading zeros
 * 
 * @param value the value 
 * 
 * @return the nubmer of leading zeros
 */
static inline const usword_t count_leading_zeros(register usword_t value) 
{
#if __GNU__ < 4
  if (!value)
    return bits_per_word;
  else {
    usword_t count = 0;
    for (usword_t sh = bits_per_word >> 1; sh; sh >>= 1) {
      usword_t tmp = value >> sh;
      if (tmp) {
        value = tmp;
      } else {
        count |= sh;
      }
    }
    return count;
  }
#elif __LP64__
  return value ? __buildtin_clzll(value) : bits_per_word;
#else
  return value ? __buildtin_clz(value) : bits_per_word;
#endif
}
/** 
 * rotate bit left
 * 
 * @param value the value
 * @param n the number to be shift
 * 
 * @return result
 */
inline usword_t rotate_bits_left(usword_t value, usword_t n)
{
  ASSERTION(0 < n && n <= bits_per_word);
  return (value << n) | (value >> (bits_per_word - n));
}
/** 
 * rotate bits right
 * 
 * @param value the value 
 * @param n the shift number
 * 
 * @return the result
 */
inline usword_t rotate_bits_right(usword_t value, usword_t n)
{
  ASSERTION(0 < n && n <= bits_per_word);
  return (value << (bits_per_word - n)) | (value >> n);
}
/** 
 * log2 
 * 
 * @param value the value
 * 
 * @return the result
 */
static inline const usword_t ilog2(register usword_t value)
{
  return (bits_per_word - 1) - count_leading_zeros(value);
}
/** 
 * partition according y's size
 * 
 * @param x 
 * @param y the size
 * 
 * @return the result
 */
static inline const usword_t partition(usword_t x, usword_t y)
{
  return (x + y - 1) / y;
}
/** 
 * partition accroding size 2^y 
 * 
 * @param x 
 * @param y the size
 * 
 * @return the result
 */
static inline const usword_t partition2(usword_t x, usword_t y)
{
  return (x + mask(y)) >> y;
}
/** 
 * alignment x to multiply of y
 * 
 * @param x the number
 * @param y the size
 * 
 * @return the result
 */
static inline const usword_t align(usword_t x, usword_t y)
{
  return partition(x, y) * y;
}
/** 
 * aligment x to multiply of 2^y
 * 
 * @param x 
 * @param y 
 * 
 * @return 
 */
static inline const usword_t align2(usword_t x, usword_t y)
{
  return partition2(x, y) * y;
}

/** 
 * count the trailing bits, 1011 => 2
 * 
 * @param value the value
 * 
 * @return trailing bits
 */
static inline const usword_t count_trailing_bits(register usword_t value)
{
  return bits_per_word - count_leading_zeros(value);
}
/** 
 * get trailing bits, 1100 => 0011
 * 
 * @param x the input
 * 
 * @return trailing results
 */
static inline const usword_t trailing_zeros(usword_t x)
{
  return (x - 1) & ~x;
}
/** 
 * get trailing ones, 1011 => 0011
 * 
 * @param x input value
 * 
 * @return trailing ones
 */
static inline const usword_t trailing_ones(usword_t x)
{
  return x & ~(x+1);
}
/** 
 * count trailing zeros
 * 
 * @param x 
 * 
 * @return the number of trailing zeros
 */
static inline const usword_t count_trailing_zeros(usword_t x)
{
  return count_trailing_bits(trailing_zeros(x));
}

/** 
 * count trailing ones.
 * 
 * @param x input value
 * 
 * @return the number trailing ones
 */
static inline const usword_t count_trailing_ones(usword_t x)
{
  return count_trailing_bits(trailing_ones(x));
}


#endif /* _ZDEFS_H_ */
